package me.sealer.ssm.config;

import me.sealer.ssm.shiro.realm.CustomShiroJdbcRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 功能描述： $ ShiroConfig
 *
 * @author sealer
 * @email 1178884049@qq.com
 * @date 2019年12月17日 15时59分43秒
 */
@Configuration
public class ShiroConfig {
    @Bean
    public SecurityManager defaultWebSecurityManager(CacheManager memoryConstrainedCacheManager, Realm customJdbcRealm, RememberMeManager rememberMeManager) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        /*缓存管理器*/
        defaultWebSecurityManager.setCacheManager(memoryConstrainedCacheManager);
        /*自定义realm*/
        defaultWebSecurityManager.setRealm(customJdbcRealm);
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager);

        return defaultWebSecurityManager;
    }

    @Bean
    public CacheManager memoryConstrainedCacheManager() {
        MemoryConstrainedCacheManager memoryConstrainedCacheManager = new MemoryConstrainedCacheManager();
        return memoryConstrainedCacheManager;
    }

    @Bean
    public Realm customJdbcRealm(CredentialsMatcher hashedCredentialsMatcher) {
        CustomShiroJdbcRealm customJdbcRealm = new CustomShiroJdbcRealm();
        customJdbcRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        /*开启缓存开关*/
        customJdbcRealm.setCachingEnabled(true);
        /*开启缓存认证信息开关*/
        customJdbcRealm.setAuthenticationCachingEnabled(true);
        /*开启缓存授权信息开关*/
        customJdbcRealm.setAuthorizationCachingEnabled(true);
        /*注入认证信息缓存bean*/
        customJdbcRealm.setAuthenticationCacheName("authenticationCache");
        /*注入授权信息缓存bean*/
        customJdbcRealm.setAuthorizationCacheName("authorizationCache");
        return customJdbcRealm;
    }

    @Bean
    public CredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(1);
        return hashedCredentialsMatcher;
    }

    @Bean
    public RememberMeManager rememberMeManager(Cookie rememberMeCookie) {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie);
        cookieRememberMeManager.setCipherKey(Base64.decode("5aaC5qKm5oqA5pyvAAABBB=="));
        return cookieRememberMeManager;
    }

    @Bean
    public Cookie rememberMeCookie() {
        Cookie rememberMeCookie = new SimpleCookie();
        /*10天*/
        rememberMeCookie.setMaxAge(10 * 24 * 60 * 60);
        /*写到cookie中的key, 可自定义设置任何合理值*/
        rememberMeCookie.setName("sealerRememberMe");
        /*通过js脚本将无法读取到cookie信息，这样能有效的防止XSS攻击*/
        rememberMeCookie.setHttpOnly(true);

        /*该属性设置后只能通过https上传cookie, http协议下不会上传cookie*/
        /*rememberMeCookie.setSecure(true);*/

        return rememberMeCookie;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager defaultWebSecurityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        shiroFilterFactoryBean.setLoginUrl("preLogin");

        // 拦截器.
        Map<String, String> map = new LinkedHashMap<>();
        map.put("preLogin", "anon");
        map.put("login", "authc");
        map.put("logout", "logout");
        map.put("**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }
}
